package baidu

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"gin/validate"
	teamones_helper "github.com/teamones-open/go-helper"
	"github.com/valyala/fasthttp"
	"mime/multipart"
	"net/http"
	"strings"
	"time"
)

// 发起 GET 请求数据
func CurlGetMethod(url string) (resData []byte, err error) {

	// 初始化http对象
	req := &fasthttp.Request{}

	// 设置路由
	req.SetRequestURI(url)

	// 设置Header
	req.Header.SetUserAgent("pan.baidu.com")

	// 设置请求方式
	req.Header.SetMethod("GET")

	// 获取请求数据
	client := &fasthttp.Client{}
	resp := &fasthttp.Response{}
	err = client.DoTimeout(req, resp, time.Second*30)

	if err != nil {
		return
	}

	// 返回body数据
	resData = resp.Body()

	return
}

// 发起 post 请求数据
func CurlPostMethod(url string, param string) (resData []byte, err error) {

	// 初始化http对象
	req := &fasthttp.Request{}

	// 设置路由
	req.SetRequestURI(url)

	// 设置Header
	req.Header.SetUserAgent("pan.baidu.com")

	// 设置Cookie
	req.Header.SetCookie("BAIDUID", "56BE0870011A115CFA43E19EA4CE92C2:FG=1")
	req.Header.SetCookie("BIDUPSID", "56BE0870011A115CFA43E19EA4CE92C2")
	req.Header.SetCookie("PSTM", "1535714267")

	// 设置请求方式
	req.Header.SetMethod("POST")

	// 增加参数
	req.SetBodyString(param)

	// 获取请求数据
	client := &fasthttp.Client{}
	resp := &fasthttp.Response{}
	err = client.DoTimeout(req, resp, time.Second*60)

	if err != nil {
		return
	}

	// 返回body数据
	resData = resp.Body()

	return
}

// PostWithFormData 发送form-data类型请求
func PostWithFormData(requestUrl string, postData map[string]string) (resp *http.Response, err error) {
	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)

	for k, v := range postData {
		_ = writer.WriteField(k, v)
	}

	_ = writer.Close()

	client := &http.Client{}

	req, err := http.NewRequest("POST", requestUrl, payload)

	if err != nil {
		return
	}
	// 设置Header
	req.Header.Set("User-Agent", "pan.baidu.com")

	// 设置Cookie
	req.Header.Set("Cookies", "BAIDUID=56BE0870011A115CFA43E19EA4CE92C2:FG=1;BIDUPSID=56BE0870011A115CFA43E19EA4CE92C2;PSTM=1535714267")
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return client.Do(req)
}

// 获取授权token信息
func GetAccessToken(code string) (accessToken AccessToken, err error) {
	requestUrl := GetAccessTokenUrl(code)

	resp, err := CurlGetMethod(requestUrl)

	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &accessToken)

	return
}

// 获取指定用户信息
func GetPanUserInfo(accessToken string) (userInfo UserInfo, err error) {
	requestUrl := GetUserInfoUrl(accessToken)

	resp, err := CurlGetMethod(requestUrl)

	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &userInfo)
	return
}

// 获取网盘容量信息
func GetPanVolume(accessToken string) (panVolume PanVolume, err error) {
	requestUrl := GetPanVolumeUrl(accessToken)

	resp, err := CurlGetMethod(requestUrl)

	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &panVolume)
	return
}

// 获取上传文件，预上传、分片上传、创建文件链接，返回上传目录地址
func GetCreatePanFileUrl(accessToken string) (uploadConfig UploadFileConfig, err error) {
	uploadConfig.Path = GetPanBasePath()

	// 预上传地址
	uploadConfig.PreCreateUrl = GetPanPreCreateUrl(accessToken)

	// 分片上传地址
	uploadConfig.UploadUrl = GetPanUploadUrl(accessToken)

	// 创建文件地址
	uploadConfig.CreateUrl = GetPanCreateUrl(accessToken)

	return
}

// 创建文件夹
func Create(accessToken string, v validate.CreatePanParam) (createPanResData CreateResData, err error) {
	requestUrl := GetPanCreateUrl(accessToken)

	paramString := []string{
		"path=" + v.Path,
		fmt.Sprintf("size=%d", v.Size),
		fmt.Sprintf("isdir=%d", v.Isdir),
		fmt.Sprintf("rtype=%d", v.Rtype), // 0 为不重命名，返回冲突 1 为只要path冲突即重命名 2 为path冲突且block_list不同才重命名 3 为覆盖

	}
	if v.Uploadid != "" {
		paramString = append(paramString, "uploadid="+v.Uploadid)
	}
	if v.BlockList != "" {
		paramString = append(paramString, "block_list="+v.BlockList)
	}
	if v.LocalCtime > 0 {
		paramString = append(paramString, fmt.Sprintf("local_ctime=%d", v.LocalCtime))
	}
	if v.LocalMtime > 0 {
		paramString = append(paramString, fmt.Sprintf("local_mtime=%d", v.LocalMtime))
	}
	if v.ZipQuality > 0 {
		paramString = append(paramString, fmt.Sprintf("zip_quality=%d", v.ZipQuality))
	}
	if v.ZipSign != "" {
		paramString = append(paramString, "zip_sign="+v.ZipSign)
	}
	if v.IsRevision > 0 {
		paramString = append(paramString, fmt.Sprintf("is_revision=%d", v.IsRevision))
	}
	if v.Mode > 0 {
		paramString = append(paramString, fmt.Sprintf("mode=%d", v.Mode))
	}
	if v.ExifInfo != "" {
		paramString = append(paramString, "exif_info="+v.ExifInfo)
	}

	fmt.Print(paramString)

	resp, err := CurlPostMethod(requestUrl, strings.Join(paramString, "&"))

	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &createPanResData)

	if createPanResData.ErrorCode != 0 {
		err = errors.New(createPanResData.ErrorMsg)
		return
	}

	if createPanResData.Errno != 0 {

		// 错误码说明
		errMsg := map[int64]string{
			2:   "param error",
			-7:  "Wrong file or directory name or no access.",
			-8:  "The file or directory already exists.",
			-10: "Cloud capacity is full.",
			10:  "Failed to create superfile for file.",
		}

		err = errors.New(fmt.Sprintf("error occured %s code [%d]", errMsg[createPanResData.Errno], createPanResData.Errno))
		return
	}

	return
}

// 获取文件列表
func GetPanFileList(accessToken string, dirName string, start, limit int64) (fileList FileList, err error) {
	requestUrl := GetPanFileListUrl(accessToken, dirName, start, limit, "")

	resp, err := CurlGetMethod(requestUrl)

	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &fileList)
	if err != nil {
		return
	}
	if fileList.Errno != 0 {
		err = errors.New(fmt.Sprintf("request for pan file list error ,error code is %d", fileList.Errno))
		return
	}

	return
}

// 获取文件列表
func GetPanFileListAll(accessToken string, dirName string, start, limit int) (fileList FileList, err error) {
	requestUrl := GetPanFileListAllUrl(accessToken, dirName, start, limit, "")

	resp, err := CurlGetMethod(requestUrl)

	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &fileList)
	if err != nil {
		return
	}
	if fileList.Errno != 0 {
		err = errors.New(fmt.Sprintf("request for pan file list error ,error code is %d", fileList.Errno))
		return
	}

	return
}

// 更新用户授权
func RefreshToken(refreshToken string) (newAccessToken NewAccessToken, err error) {
	requestUrl := GetRefreshTokenUrl(refreshToken)

	resp, err := CurlGetMethod(requestUrl)

	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &newAccessToken)
	if err == nil && newAccessToken.Error != "" {
		err = errors.New(fmt.Sprintf("%s   %s", newAccessToken.Error, newAccessToken.ErrorDescription))
	}
	return
}

// 获取指定文件的下载链接
func GetPanFileDownloadUrl(accessToken string, Fsids []uint64) (fileDownLoadRes FileDownLoadRes, err error) {

	requestUrl := GetFileMetasUrl(accessToken, Fsids, 0, 1, 0)

	resp, err := CurlGetMethod(requestUrl)
	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &fileDownLoadRes)

	if fileDownLoadRes.Errno != 0 {
		err = errors.New(fileDownLoadRes.Errmsg)
		return
	}

	return
}

// FileManage 文件管理
func FileManage(accessToken, Opra string, Async int, FileList string, Ondup string) (res FileManageRes, err error) {
	requestUrl := GetFileManageUrl(accessToken, Opra)
	paramMap := map[string]string{
		"async":    teamones_helper.StrVal(Async),
		"filelist": FileList,
	}
	if Ondup != "" {
		paramMap["ondup"] = Ondup
	}
	paramStr := make([]string, len(paramMap))
	index := 0
	for k, v := range paramMap {
		paramStr[index] = k + "=" + v
		index += 1
	}

	body, err := CurlPostMethod(requestUrl, strings.Join(paramStr, "&"))

	if err != nil {
		return
	}

	err = json.Unmarshal(body, &res)
	return
}

// GetFileMetaInfo 查询文件信息
func GetFileMetaInfo(token string, fsidList []uint64, thumb, dlink, extra int) (fileMetas FileMetaResp, err error) {
	requestUrl := GetFileMetasUrl(token, fsidList, 0, 1, 0)
	resp, err := CurlGetMethod(requestUrl)

	if err != nil {
		return
	}

	err = json.Unmarshal(resp, &fileMetas)
	return
}
